package com.pig4cloud.pigx.user.util;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
import com.pig4cloud.pigx.system.constant.EmailTemplateTypeEnum;
import com.pig4cloud.pigx.system.dto.ArticleInformationDTO;
import com.pig4cloud.pigx.system.util.SendEmailUtil;
import com.pig4cloud.pigx.user.api.feign.DuckweedRemoteSystemService;
import com.pig4cloud.pigx.user.entity.ArticleInformation;
import com.pig4cloud.pigx.user.entity.RechargeRecord;
import com.pig4cloud.pigx.user.entity.User;
import com.pig4cloud.pigx.user.constant.WalletEmailTemplateConstants;
import lombok.AllArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Component;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

import static com.pig4cloud.pigx.user.constant.I18nMessages.EMAIL_TEMPLATE_TYPE_DOSE_NOT_EXIST;

/**
 * 邮件发送器
 *
 * @since 2022/9/14 14:52
 */
@Component
@AllArgsConstructor
public class WalletEmailSender {

	/**
	 * Roo邮件发送工具类
	 */
	private final SendEmailUtil sendEmailUtil;

	private final DuckweedRemoteSystemService duckweedRemoteSystemService;
	public static Session mailSession = null;

	/**
	 * 发送充值成功邮件
	 *
	 * @param record 充值记录
	 * @since 2022/9/27 10:07
	 */
	public void sendRecharge(RechargeRecord record, User user) throws MessagingException {
		// 根据模板编码、语言获得对应的邮箱编码
		ArticleInformation info = getContext(EmailTemplateTypeEnum.RECHARGED_SUCCESSFULLY.getArticleTypeCode(), null);
		String content = info.getTextContent();
		// 获取时间
		DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String dateStr = LocalDateTime.now().format(format);
		info.setTitle(info.getTitle().replace("${time}",dateStr));
		if (Strings.isEmpty(content)) {
			return;
		}

		// 编辑模板信息
		content = content.replace("${quantity}", record.getQuantity().stripTrailingZeros().toPlainString());

		// 发送邮件
		sendEmail(info.getTitle(), content, user.getEmail());
	}

	/**
	 * 发送提现成功邮件
	 *
	 * @param actualWithdrawalAmount 实际提现金额
	 * @param arrivalAddress         到账地址
	 * @param transactionHash        交易hash
	 * @since 2022/9/27 10:07
	 */
	public void sendWithdrawal(String actualWithdrawalAmount, String arrivalAddress, String transactionHash, User user) throws MessagingException {
		// 根据模板编码、语言获得对应的邮箱编码
		ArticleInformation info = getContext(WalletEmailTemplateConstants.WITHDRAWAL, null);
		String content = info.getTextContent();
		content = content.replace("${time}", LocalDateTime.now().toString());
		if (Strings.isEmpty(content)) {
			return;
		}

		// 编辑模板信息
		content = content.replace("${actualWithdrawalAmount}", actualWithdrawalAmount)
				.replace("${arrivalAddress}", arrivalAddress)
				.replace("${transactionHash}", transactionHash);

		// 发送邮件
		sendEmail(info.getTitle(), content, user.getEmail());
	}

	/**
	 * 发送确认提现验证码邮件
	 *
	 * @param actualWithdrawalAmount 实际提现金额
	 * @param arrivalAddress         到账地址
	 * @param code                   提现验证码
	 * @since 2022/9/28 10:07
	 */
	public void sendConfirmwithdrawal(String actualWithdrawalAmount, String arrivalAddress, String code, User user) throws MessagingException {
		// 根据模板编码、语言获得对应的邮箱编码
		ArticleInformation info = getContext(WalletEmailTemplateConstants.CONFIRM_WITHDRAWAL, null);
		String content = info.getTextContent();
		if (Strings.isEmpty(content)) {
			return;
		}

		// 编辑模板信息
		content = content.replace("${actualWithdrawalAmount}", actualWithdrawalAmount)
				.replace("${arrivalAddress}", arrivalAddress)
				.replace("${code}", code);

		// 发送邮件
		sendEmail(info.getTitle(), content, user.getEmail());
	}

	/**
	 * 后台资金人工充值
	 *
	 * @param titleCode
	 * @param textContentCode
	 * @param email
	 * @param articleInformationDTO
	 * @param type
	 */
	public void sendRechargeCapitalAccount(Map<String, String> titleCode, Map<String, String> textContentCode,
										   String email, ArticleInformationDTO articleInformationDTO, String type) {
		// 充值邮箱模板
		articleInformationDTO.setArticleTypeCode(EmailTemplateTypeEnum.FUND_ACCOUNT_BACKGROUND_RECHARGE.getArticleTypeCode());
		// system 发送邮件工具类
		sendEmailUtil.sendEmail(titleCode, textContentCode, email, articleInformationDTO);
	}

	/**
	 * 根据模板编码、语言获得对应的邮箱编码
	 *
	 * @param templateCode 模板编码
	 * @param language     语言
	 * @return {@link ArticleInformation}
	 * @since 2022/9/14 15:14
	 */
	public ArticleInformation getContext(String templateCode, String language) throws MessagingException {
		// 组装模板查询参数
		ArticleInformation condition = new ArticleInformation();
		// 邮件模板编码
		condition.setArticleTypeCode(templateCode);
		// 邮箱模板语言，当前语言为空则返回中文
		condition.setLanguageId(Strings.isEmpty(language) ? "zh_CN" : language);

		R<List<ArticleInformation>> templateR = duckweedRemoteSystemService.getArticleManagementFeign(condition, SecurityConstants.FROM_IN);
		List<ArticleInformation> templateList = templateR.getData();
		// 判断数据获取是否成功
		if (CollectionUtils.isEmpty(templateList)) {
			// 在消息监听中处理失败时，不回滚消息
			throw new MessagingException(MessageUtils.get(EMAIL_TEMPLATE_TYPE_DOSE_NOT_EXIST));
		}

		// 返回下标0的模板
		return templateList.get(0);
	}

	/**
	 * 发送邮件
	 *
	 * @param title   标题
	 * @param content 内容
	 * @param email   邮箱
	 * @since 2022/9/14 15:25
	 */
	private void sendEmail(String title, String content, String email) throws MessagingException {
		// 获取邮件会话
		Session mailSession = getMailSession();
		// 创建邮件消息
		MimeMessage message = new MimeMessage(mailSession);

		try {
			// 设置发件人
			InternetAddress form = new InternetAddress(ParamResolver.getStr("MAIL_USER", ""),
					ParamResolver.getStr("MAIL_SENDER"), "UTF-8");
			message.setFrom(form);

			// 设置收件人
			InternetAddress to = new InternetAddress(email);
			message.setRecipient(Message.RecipientType.TO, to);
			// 设置标题
			message.setSubject(title);
			// 设置内容
			message.setContent(content, "text/html;charset=UTF-8");
			// 发送邮件
			Transport.send(message);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 获取邮件会话
	 *
	 * @return {@link Session}
	 * @since 2022/9/26 21:26
	 */
	private static Session getMailSession() {
		if (!Objects.isNull(mailSession)) {
			return mailSession;
		}

		// 获取配置属性
		final Properties props = getProps();
		// 根据配置属性获取授权信息
		Authenticator authenticator = getAuth(props);

		// 使用环境属性和授权信息，创建邮件会话
		mailSession = Session.getInstance(props, authenticator);

		return mailSession;
	}

	/**
	 * 根据配置属性获获取授权信息
	 *
	 * @param props 配置属性
	 * @return {@link Authenticator}
	 * @since 2022/9/14 15:24
	 */
	private static Authenticator getAuth(Properties props) {
		// 构建授权信息，用于进行SMTP进行身份验证
		return new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				// 用户名、密码
				String userName = props.getProperty("mail.user");
				String password = props.getProperty("mail.password");
				return new PasswordAuthentication(userName, password);
			}
		};
	}

	/**
	 * 获取配置属性
	 *
	 * @return {@link Properties}
	 * @since 2022/9/14 15:24
	 */
	private static Properties getProps() {
		// 配置发送邮件的环境属性
		final Properties props = new Properties();
		// 发送邮件协议名称
		props.setProperty("mail.transport.protocol", ParamResolver.getStr("MAIL_TRANSPORT_PROTOCOL", "smtp"));
		// 表示SMTP发送邮件，发送服务器需要进行身份验证
		props.put("mail.smtp.auth", ParamResolver.getStr("MAIL_SMTP_AUTH", "true"));
		// 设置邮件服务器主机名
		props.put("mail.smtp.host", ParamResolver.getStr("MAIL_SMTP_HOST", "smtp.qq.com"));
		// smtp登陆的账号、密码 ；需开启smtp登陆
		props.put("mail.user", ParamResolver.getStr("MAIL_USER", ""));
		// 访问SMTP服务时需要提供的密码,不是邮箱登陆密码，一般都有独立smtp的登陆密码
		props.put("mail.password", ParamResolver.getStr("MAIL_PASSWORD", ""));

		// 邮件SMTP时间限制,单位毫秒。这个是有关邮件读取时间长短。默认是无限制。
		props.put("mail.smtp.timeout", 30000);
		// 阿里云25端口默认禁用，使用465SSL接口
		props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.put("mail.smtp.socketFactory.port", "465");
		props.put("mail.smtp.port", "465");
		// 连接时间限制，单位毫秒。是关于与邮件服务器建立连接的时间长短的。默认是无限制
		props.put("mail.smtp.connectiontimeout", 30000);
		// 邮件发送时间限制，单位毫秒。看关发送邮件时内容上传的时间长短。默认同样是无限制。
		props.put("mail.smtp.writetimeout", 30000);


		return props;
	}
}
